#!/bin/bash
###############################################################################
#       脚本名称: config.sh
#       功能描述: 统一配置管理模块，提供格式无关的配置操作API。
#       作者: 林再来
#       日期: 2025-10-20
#       版本: 1.0
#       功能:
#           1、初始化配置文件
#           2、加载配置文件(支持YAML、JSON、ENV、INI、TOML、Properties格式)
#           3、读取配置值(支持默认值、自动重载)
#           4、写入配置值(支持类型、原子操作)
#           5、配置值导出和备份(支持YAML、JSON、ENV、INI、TOML、Properties格式)
#           6、格式自动识别(根据文件扩展名)
#           7、配置缓存管理(基于哈希值的失效策略)
#       依赖(插件/命令):
#           1、yaml.sh - YAML格式处理器
#           2、json.sh - JSON格式处理器
#           3、env.sh - ENV格式处理器
#           4、ini.sh - INI格式处理器
#           5、toml.sh - TOML格式处理器(可选)
#           6、properties.sh - Properties格式处理器(可选)
###############################################################################

# 防止重复加载
if [[ -n "${config_sh_loaded:-}" ]]; then
    return 0
fi
readonly config_sh_loaded=1

# 注意：不使用 set -euo pipefail 严格模式
# 原因：
# 1. 该脚本会被 source 到交互式 shell 中
# 2. 严格模式会影响整个 shell 环境，导致任何错误都退出 shell
# 3. 我们通过显式的错误检查和返回值来保证代码质量

# 获取脚本目录和项目根目录
# 使用模块特定的变量名避免与其他模块冲突
if [[ -z "${_config_script_dir:-}" ]]; then
    _config_script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    readonly _config_script_dir
fi

if [[ -z "${project_root:-}" ]]; then
    project_root="$(cd "${_config_script_dir}/../.." && pwd)"
    readonly project_root
fi

###############################################################################
# 全局数据结构
###############################################################################

# 配置文件信息
declare -A CONFIG_FILES          # 配置标识符 -> 文件路径
declare -A CONFIG_FILE_FORMAT    # 配置标识符 -> 文件格式
declare -A CONFIG_FILE_HASH      # 配置标识符 -> 文件哈希
declare -A CONFIG_DIRTY          # 配置标识符 -> 是否有未保存修改

# 配置缓存(可选，用于全量缓存)
declare -A CONFIG_CACHE          # 缓存键 -> 值

# 待保存的修改（用于批量保存）
# 格式: CONFIG_PENDING_CHANGES["config_id:index"]="operation_type|key|value|value_type"
declare -A CONFIG_PENDING_CHANGES

# 待保存修改的计数器
declare -A CONFIG_PENDING_COUNT  # 配置标识符 -> 待保存修改数量

# 已加载的格式处理器
declare -A FORMAT_HANDLERS_LOADED

###############################################################################
# 全局配置
###############################################################################

# 是否自动检测变更并重载
CONFIG_AUTO_RELOAD="${CONFIG_AUTO_RELOAD:-true}"

# 是否启用缓存（当前版本使用文件级缓存，即检查哈希）
CONFIG_CACHE_ENABLED="${CONFIG_CACHE_ENABLED:-true}"

# 监控检查间隔(秒)
CONFIG_WATCH_INTERVAL="${CONFIG_WATCH_INTERVAL:-5}"

###############################################################################
# 内部辅助函数
###############################################################################

# 函数: 加载格式处理器
# 功能: 动态加载指定格式的处理器脚本
# 参数: $1 - 格式名称(yaml/json/env/ini)
# 返回: 0-成功, 1-失败
function _config_load_handler() {
    local format="$1"
    local handler_dir="$_config_script_dir"  # 使用不同的变量名，避免与 readonly script_dir 冲突
    
    # 检查是否已加载
    if [[ "${FORMAT_HANDLERS_LOADED[$format]:-}" == "true" ]]; then
        return 0
    fi
    
    # 加载对应的处理器脚本
    case "$format" in
        yaml|yml)
            if [[ -f "$handler_dir/yaml.sh" ]]; then
                source "$handler_dir/yaml.sh" || {
                    log_error "config" "加载YAML配置适配器失败"
                    return 1
                }
                FORMAT_HANDLERS_LOADED["yaml"]="true"
                log_debug "config" "YAML配置适配器加载成功"
            else
                log_error "config" "YAML配置适配器文件不存在: $handler_dir/yaml.sh"
                return 1
            fi
            ;;
        json)
            if [[ -f "$handler_dir/json.sh" ]]; then
                source "$handler_dir/json.sh" || {
                    log_error "config" "加载JSON配置适配器失败"
                    return 1
                }
                FORMAT_HANDLERS_LOADED["json"]="true"
                log_debug "config" "JSON配置适配器加载成功"
            else
                log_error "config" "JSON配置适配器文件不存在: $handler_dir/json.sh"
                return 1
            fi
            ;;
        env)
            if [[ -f "$handler_dir/env.sh" ]]; then
                source "$handler_dir/env.sh" || {
                    log_error "config" "加载ENV处理器失败"
                    return 1
                }
                FORMAT_HANDLERS_LOADED["env"]="true"
                log_debug "config" "ENV处理器加载成功"
            else
                log_error "config" "ENV处理器文件不存在: $handler_dir/env.sh"
                return 1
            fi
            ;;
        ini)
            if [[ -f "$handler_dir/ini.sh" ]]; then
                source "$handler_dir/ini.sh" || {
                    log_error "config" "加载INI处理器失败"
                    return 1
                }
                FORMAT_HANDLERS_LOADED["ini"]="true"
                log_debug "config" "INI处理器加载成功"
            else
                log_error "config" "INI处理器文件不存在: $handler_dir/ini.sh"
                return 1
            fi
            ;;
        toml)
            if [[ -f "$handler_dir/toml.sh" ]]; then
                source "$handler_dir/toml.sh" || {
                    log_error "config" "加载TOML处理器失败"
                    return 1
                }
                FORMAT_HANDLERS_LOADED["toml"]="true"
                log_debug "config" "TOML处理器加载成功"
            else
                log_warn "config" "TOML处理器文件不存在，暂不支持TOML格式"
                return 1
            fi
            ;;
        properties)
            if [[ -f "$handler_dir/properties.sh" ]]; then
                source "$handler_dir/properties.sh" || {
                    log_error "config" "加载Properties处理器失败"
                    return 1
                }
                FORMAT_HANDLERS_LOADED["properties"]="true"
                log_debug "config" "Properties处理器加载成功"
            else
                log_warn "config" "Properties处理器文件不存在，暂不支持Properties格式"
                return 1
            fi
            ;;
        *)
            log_error "config" "不支持的配置格式: $format"
            return 1
            ;;
    esac
    
    return 0
}

# 函数: 识别配置文件格式
# 功能: 根据文件扩展名自动识别配置格式
# 参数: $1 - 配置文件路径
# 返回: 输出格式名称(stdout)
function _config_detect_format() {
    local config_file="$1"
    
    # 提取文件扩展名
    local extension="${config_file##*.}"
    extension="${extension,,}"  # 转小写
    
    # 根据扩展名映射格式
    case "$extension" in
        yaml|yml)
            echo "yaml"
            ;;
        json)
            echo "json"
            ;;
        env)
            echo "env"
            ;;
        ini|conf|cfg)
            echo "ini"
            ;;
        toml)
            echo "toml"
            ;;
        properties)
            echo "properties"
            ;;
        *)
            log_warn "config" "未知文件格式: $extension，尝试作为INI处理"
            echo "ini"
            ;;
    esac
}

# 函数: 计算文件哈希值
# 功能: 计算配置文件的哈希值，用于检测变更
# 参数: $1 - 配置文件路径
# 返回: 输出哈希值(stdout)
function _config_calculate_hash() {
    local config_file="$1"
    
    # 三级降级策略
    if command -v md5sum >/dev/null 2>&1; then
        # 首选：md5sum
        md5sum "$config_file" 2>/dev/null | cut -d' ' -f1
    elif command -v cksum >/dev/null 2>&1; then
        # 备选：cksum
        cksum "$config_file" 2>/dev/null | cut -d' ' -f1
    else
        # 降级：文件大小 + 修改时间
        local file_size
        local file_mtime
        
        if [[ "$(uname)" == "Linux" ]]; then
            file_size=$(stat -c "%s" "$config_file" 2>/dev/null || echo "0")
            file_mtime=$(stat -c "%Y" "$config_file" 2>/dev/null || echo "0")
        else
            # macOS/BSD
            file_size=$(stat -f "%z" "$config_file" 2>/dev/null || echo "0")
            file_mtime=$(stat -f "%m" "$config_file" 2>/dev/null || echo "0")
        fi
        
        echo "${file_size}-${file_mtime}"
    fi
}

###############################################################################
# 公共API函数
###############################################################################

# 函数: 初始化配置系统
# 功能: 初始化配置管理模块，预加载常用处理器
# 参数: 无
# 返回: 0-成功, 1-失败
function config_init() {
    log_info "config" "初始化配置管理系统"
    
    # 预加载YAML处理器（最常用）
    if _config_load_handler "yaml"; then
        log_debug "config" "预加载YAML处理器成功"
    else
        log_warn "config" "预加载YAML处理器失败，将在使用时按需加载"
    fi
    
    log_info "config" "配置管理系统初始化完成"
    return 0
}

# 函数: 加载配置文件
# 功能: 加载配置文件到系统，验证格式并缓存信息
# 参数:
#   $1 - 配置文件路径
#   $2 - 配置标识符(可选，默认使用文件名)
#   $3 - 是否强制重载(可选，默认false)
# 返回: 0-成功, 1-失败
# 示例:
#   config_load "config/logger.yaml" "logger"
#   config_load "config/mysql.ini" "mysql" true
function config_load() {
    local config_file="$1"
    local config_id="${2:-}"
    local force_reload="${3:-false}"
    
    # 如果未指定配置ID，从文件名提取（去除扩展名）
    if [[ -z "$config_id" ]]; then
        config_id=$(basename "$config_file" | sed 's/\.[^.]*$//')
    fi
    
    log_debug "config" "加载配置: $config_file (ID: $config_id)"
    
    # 检查文件存在性
    if [[ ! -f "$config_file" ]]; then
        log_error "config" "配置文件不存在: $config_file"
        return 1
    fi
    
    # 转换为绝对路径
    config_file="$(cd "$(dirname "$config_file")" && pwd)/$(basename "$config_file")"
    
    # 识别配置格式
    local format
    format=$(_config_detect_format "$config_file")
    log_debug "config" "识别配置格式: $format"
    
    # 加载格式处理器
    if ! _config_load_handler "$format"; then
        log_error "config" "加载格式处理器失败: $format"
        return 1
    fi
    
    # 检查缓存（如果不是强制重载）
    if [[ "$force_reload" != "true" ]] && [[ -n "${CONFIG_FILES[$config_id]:-}" ]]; then
        local current_hash
        current_hash=$(_config_calculate_hash "$config_file")
        
        if [[ "${CONFIG_FILE_HASH[$config_id]:-}" == "$current_hash" ]]; then
            log_debug "config" "配置未变更，使用缓存: $config_id"
            return 0
        fi
        
        log_info "config" "检测到配置变更，重新加载: $config_id"
    fi
    
    # 验证配置文件格式
    log_debug "config" "验证配置文件格式: $format"
    case "$format" in
        yaml)
            if ! utils_yq_validate "$config_file"; then
                log_error "config" "YAML文件格式验证失败: $config_file"
                return 1
            fi
            ;;
        json)
            if ! utils_jq_validate "$config_file"; then
                log_error "config" "JSON文件格式验证失败: $config_file"
                return 1
            fi
            ;;
        env)
            if ! env_validate "$config_file"; then
                log_error "config" "ENV文件格式验证失败: $config_file"
                return 1
            fi
            ;;
        ini)
            if ! ini_validate "$config_file"; then
                log_error "config" "INI文件格式验证失败: $config_file"
                return 1
            fi
            ;;
        toml)
            if command -v toml_validate >/dev/null 2>&1; then
                if ! toml_validate "$config_file"; then
                    log_error "config" "TOML文件格式验证失败: $config_file"
                    return 1
                fi
            else
                log_warn "config" "TOML验证函数不可用，跳过验证"
            fi
            ;;
        properties)
            if command -v properties_validate >/dev/null 2>&1; then
                if ! properties_validate "$config_file"; then
                    log_error "config" "Properties文件格式验证失败: $config_file"
                    return 1
                fi
            else
                log_warn "config" "Properties验证函数不可用，跳过验证"
            fi
            ;;
        *)
            log_warn "config" "未知格式，跳过验证: $format"
            ;;
    esac
    
    # 计算文件哈希值
    local file_hash
    file_hash=$(_config_calculate_hash "$config_file")
    
    # 保存配置信息到全局变量
    CONFIG_FILES["$config_id"]="$config_file"
    CONFIG_FILE_FORMAT["$config_id"]="$format"
    CONFIG_FILE_HASH["$config_id"]="$file_hash"
    CONFIG_DIRTY["$config_id"]="false"
    
    log_info "config" "配置加载成功: $config_id ($format) [hash: ${file_hash:0:8}...]"
    return 0
}

# 函数: 读取配置值
# 功能: 从配置中读取指定键的值
# 参数:
#   $1 - 配置标识符
#   $2 - 键路径
#   $3 - 默认值(可选)
# 返回: 配置值(stdout), 0-成功, 1-失败
# 示例:
#   log_level=$(config_get "logger" ".logger.global.level" "INFO")
#   db_port=$(config_get "mysql" "database.port" "3306")
function config_get() {
    local config_id="$1"
    local key="$2"
    local default_value="${3:-}"
    
    log_debug "config" "读取配置: $config_id -> $key"
    
    # 检查配置是否已加载
    if [[ -z "${CONFIG_FILES[$config_id]:-}" ]]; then
        log_error "config" "配置未加载: $config_id"
        
        # 提供友好的错误提示
        if [[ ${#CONFIG_FILES[@]} -gt 0 ]]; then
            log_warn "config" "可用的配置ID: ${!CONFIG_FILES[*]}"
            log_warn "config" "提示: 请检查配置ID拼写或使用 config_list 查看详情"
        fi
        
        echo "$default_value"
        return 1
    fi
    
    local config_file="${CONFIG_FILES[$config_id]}"
    local format="${CONFIG_FILE_FORMAT[$config_id]}"
    
    # 自动重载检查
    if [[ "$CONFIG_AUTO_RELOAD" == "true" ]]; then
        local current_hash
        current_hash=$(_config_calculate_hash "$config_file")
        
        if [[ "${CONFIG_FILE_HASH[$config_id]}" != "$current_hash" ]]; then
            log_info "config" "检测到配置变更，自动重载: $config_id"
            if config_load "$config_file" "$config_id" true; then
                log_debug "config" "配置重载成功"
            else
                log_warn "config" "配置重载失败，使用旧配置"
            fi
        fi
    fi
    
    # 调用对应格式处理器读取
    local value=""
    case "$format" in
        yaml)
            value=$(yaml_read "$config_file" "$key" 2>/dev/null) || value=""
            ;;
        json)
            value=$(json_read "$config_file" "$key" 2>/dev/null) || value=""
            ;;
        env)
            value=$(env_read "$config_file" "$key" 2>/dev/null) || value=""
            ;;
        ini)
            # INI格式键路径: section.key
            local section="${key%%.*}"
            local ini_key="${key#*.}"
            
            # 如果没有点号，说明格式不对
            if [[ "$section" == "$key" ]]; then
                log_error "config" "INI格式键路径格式错误，应为 section.key: $key"
                echo "$default_value"
                return 1
            fi
            
            value=$(ini_read "$config_file" "$section" "$ini_key" 2>/dev/null) || value=""
            ;;
        toml)
            if command -v toml_read >/dev/null 2>&1; then
                value=$(toml_read "$config_file" "$key" 2>/dev/null) || value=""
            else
                log_error "config" "TOML读取函数不可用"
                echo "$default_value"
                return 1
            fi
            ;;
        properties)
            if command -v properties_read >/dev/null 2>&1; then
                value=$(properties_read "$config_file" "$key" 2>/dev/null) || value=""
            else
                log_error "config" "Properties读取函数不可用"
                echo "$default_value"
                return 1
            fi
            ;;
        *)
            log_error "config" "不支持的格式: $format"
            echo "$default_value"
            return 1
            ;;
    esac
    
    # 返回值或默认值
    if [[ -n "$value" ]]; then
        echo "$value"
        log_debug "config" "读取成功: $config_id -> $key = $value"
        return 0
    else
        echo "$default_value"
        log_debug "config" "读取为空，返回默认值: $config_id -> $key = $default_value"
        return 0
    fi
}

# 函数: 写入配置值
# 功能: 设置配置中指定键的值
# 参数:
#   $1 - 配置标识符
#   $2 - 键路径
#   $3 - 值
#   $4 - 值类型(可选: string/number/boolean，默认string)
#   $5 - 是否立即保存(可选，默认true)
# 返回: 0-成功, 1-失败
# 示例:
#   config_set "logger" ".logger.global.level" "DEBUG"
#   config_set "mysql" "database.port" "3307" "number"
function config_set() {
    local config_id="$1"
    local key="$2"
    local value="$3"
    local value_type="${4:-string}"
    local save_now="${5:-true}"
    
    log_debug "config" "写入配置: $config_id -> $key = $value ($value_type)"
    
    # 检查配置是否已加载
    if [[ -z "${CONFIG_FILES[$config_id]:-}" ]]; then
        log_error "config" "配置未加载: $config_id"
        
        # 提供友好的错误提示
        if [[ ${#CONFIG_FILES[@]} -gt 0 ]]; then
            log_warn "config" "可用的配置ID: ${!CONFIG_FILES[*]}"
            log_warn "config" "提示: 请检查配置ID拼写或使用 config_list 查看详情"
        fi
        
        return 1
    fi
    
    local config_file="${CONFIG_FILES[$config_id]}"
    local format="${CONFIG_FILE_FORMAT[$config_id]}"
    
    # 如果不立即保存，则将修改加入待保存队列
    if [[ "$save_now" != "true" ]]; then
        # 获取当前待保存修改的数量
        local count="${CONFIG_PENDING_COUNT[$config_id]:-0}"
        
        # 存储待保存的修改
        CONFIG_PENDING_CHANGES["${config_id}:${count}"]="set|${key}|${value}|${value_type}"
        
        # 更新计数器
        CONFIG_PENDING_COUNT["$config_id"]=$((count + 1))
        
        # 标记配置为dirty
        CONFIG_DIRTY["$config_id"]="true"
        
        log_debug "config" "配置修改已加入待保存队列: $config_id -> $key = $value (待保存数: $((count + 1)))"
        return 0
    fi
    
    # 立即保存模式：直接调用格式处理器写入
    case "$format" in
        yaml)
            if ! yaml_write "$config_file" "$key" "$value" "$value_type"; then
                log_error "config" "YAML写入失败"
                return 1
            fi
            ;;
        json)
            if ! json_write "$config_file" "$key" "$value" "$value_type"; then
                log_error "config" "JSON写入失败"
                return 1
            fi
            ;;
        env)
            # ENV格式不支持类型，所有值都是字符串
            if ! env_write "$config_file" "$key" "$value"; then
                log_error "config" "ENV写入失败"
                return 1
            fi
            ;;
        ini)
            # INI格式键路径: section.key
            local section="${key%%.*}"
            local ini_key="${key#*.}"
            
            if [[ "$section" == "$key" ]]; then
                log_error "config" "INI格式键路径格式错误，应为 section.key: $key"
                return 1
            fi
            
            if ! ini_write "$config_file" "$section" "$ini_key" "$value"; then
                log_error "config" "INI写入失败"
                return 1
            fi
            ;;
        toml)
            if command -v toml_write >/dev/null 2>&1; then
                if ! toml_write "$config_file" "$key" "$value" "$value_type"; then
                    log_error "config" "TOML写入失败"
                    return 1
                fi
            else
                log_error "config" "TOML写入函数不可用"
                return 1
            fi
            ;;
        properties)
            if command -v properties_write >/dev/null 2>&1; then
                if ! properties_write "$config_file" "$key" "$value"; then
                    log_error "config" "Properties写入失败"
                    return 1
                fi
            else
                log_error "config" "Properties写入函数不可用"
                return 1
            fi
            ;;
        *)
            log_error "config" "不支持的格式: $format"
            return 1
            ;;
    esac
    
    # 更新文件哈希值
    CONFIG_FILE_HASH["$config_id"]=$(_config_calculate_hash "$config_file")
    
    # 清除dirty标记（已立即保存）
    CONFIG_DIRTY["$config_id"]="false"
    
    log_info "config" "配置写入成功: $config_id -> $key = $value"
    return 0
}

# 函数: 删除配置项
# 功能: 从配置中删除指定的键
# 参数:
#   $1 - 配置标识符
#   $2 - 键路径
#   $3 - 是否立即保存(可选，默认true)
# 返回: 0-成功, 1-失败
# 示例:
#   config_delete "logger" ".logger.test_key"
function config_delete() {
    local config_id="$1"
    local key="$2"
    local save_now="${3:-true}"
    
    log_debug "config" "删除配置: $config_id -> $key"
    
    # 检查配置是否已加载
    if [[ -z "${CONFIG_FILES[$config_id]:-}" ]]; then
        log_error "config" "配置未加载: $config_id"
        
        # 提供友好的错误提示
        if [[ ${#CONFIG_FILES[@]} -gt 0 ]]; then
            log_warn "config" "可用的配置ID: ${!CONFIG_FILES[*]}"
            log_warn "config" "提示: 请检查配置ID拼写或使用 config_list 查看详情"
        fi
        
        return 1
    fi
    
    local config_file="${CONFIG_FILES[$config_id]}"
    local format="${CONFIG_FILE_FORMAT[$config_id]}"
    
    # 如果不立即保存，则将删除操作加入待保存队列
    if [[ "$save_now" != "true" ]]; then
        # 获取当前待保存修改的数量
        local count="${CONFIG_PENDING_COUNT[$config_id]:-0}"
        
        # 存储待保存的删除操作
        CONFIG_PENDING_CHANGES["${config_id}:${count}"]="delete|${key}||"
        
        # 更新计数器
        CONFIG_PENDING_COUNT["$config_id"]=$((count + 1))
        
        # 标记配置为dirty
        CONFIG_DIRTY["$config_id"]="true"
        
        log_debug "config" "配置删除操作已加入待保存队列: $config_id -> $key (待保存数: $((count + 1)))"
        return 0
    fi
    
    # 立即保存模式：直接调用格式处理器删除
    case "$format" in
        yaml)
            if ! yaml_delete "$config_file" "$key"; then
                log_error "config" "YAML删除失败"
                return 1
            fi
            ;;
        json)
            if command -v json_delete >/dev/null 2>&1; then
                if ! json_delete "$config_file" "$key"; then
                    log_error "config" "JSON删除失败"
                    return 1
                fi
            else
                log_error "config" "JSON删除函数不可用"
                return 1
            fi
            ;;
        env)
            if command -v env_delete >/dev/null 2>&1; then
                if ! env_delete "$config_file" "$key"; then
                    log_error "config" "ENV删除失败"
                    return 1
                fi
            else
                log_error "config" "ENV删除函数不可用"
                return 1
            fi
            ;;
        ini)
            local section="${key%%.*}"
            local ini_key="${key#*.}"
            
            if [[ "$section" == "$key" ]]; then
                log_error "config" "INI格式键路径格式错误，应为 section.key: $key"
                return 1
            fi
            
            if command -v ini_delete >/dev/null 2>&1; then
                if ! ini_delete "$config_file" "$section" "$ini_key"; then
                    log_error "config" "INI删除失败"
                    return 1
                fi
            else
                log_error "config" "INI删除函数不可用"
                return 1
            fi
            ;;
        *)
            log_error "config" "不支持的格式: $format"
            return 1
            ;;
    esac
    
    # 更新文件哈希值
    CONFIG_FILE_HASH["$config_id"]=$(_config_calculate_hash "$config_file")
    
    # 清除dirty标记（已立即保存）
    CONFIG_DIRTY["$config_id"]="false"
    
    log_info "config" "配置删除成功: $config_id -> $key"
    return 0
}

# 函数: 重新加载配置
# 功能: 从文件重新加载配置，刷新缓存
# 参数:
#   $1 - 配置标识符
# 返回: 0-成功, 1-失败
# 示例:
#   config_reload "logger"
function config_reload() {
    local config_id="$1"
    
    log_debug "config" "重新加载配置: $config_id"
    
    # 检查配置是否已加载
    if [[ -z "${CONFIG_FILES[$config_id]:-}" ]]; then
        log_error "config" "配置未加载: $config_id"
        
        # 提供友好的错误提示
        if [[ ${#CONFIG_FILES[@]} -eq 0 ]]; then
            log_warn "config" "当前没有已加载的配置。请先使用 config_load 加载配置文件"
            log_warn "config" "示例: config_load \"config/logger.yaml\" \"logger\""
        else
            log_warn "config" "可用的配置ID列表："
            for id in "${!CONFIG_FILES[@]}"; do
                log_warn "config" "  - $id (${CONFIG_FILE_FORMAT[$id]}: ${CONFIG_FILES[$id]})"
            done
            log_warn "config" "提示: 请检查配置ID拼写是否正确"
        fi
        return 1
    fi
    
    local config_file="${CONFIG_FILES[$config_id]}"
    
    # 强制重新加载
    if config_load "$config_file" "$config_id" true; then
        log_info "config" "配置重新加载成功: $config_id"
        return 0
    else
        log_error "config" "配置重新加载失败: $config_id"
        return 1
    fi
}

# 函数: 保存配置到文件
# 功能: 将待保存的配置修改批量写入文件
# 参数:
#   $1 - 配置标识符(可选，默认保存所有dirty的配置)
#   $2 - 目标文件路径(可选，默认保存到原文件)
# 返回: 0-成功, 1-失败
# 示例:
#   config_save "logger"                          # 保存到原文件
#   config_save "logger" "backup/logger.yaml"     # 保存到指定文件
#   config_save                                   # 保存所有配置到原文件
function config_save() {
    local target_config_id="${1:-}"
    local target_file="${2:-}"
    local saved_count=0
    local failed_count=0
    
    # 如果指定了配置ID，只保存该配置
    if [[ -n "$target_config_id" ]]; then
        # 检查配置是否已加载
        if [[ -z "${CONFIG_FILES[$target_config_id]:-}" ]]; then
            log_error "config" "配置未加载: $target_config_id"
            
            if [[ ${#CONFIG_FILES[@]} -gt 0 ]]; then
                log_warn "config" "可用的配置ID: ${!CONFIG_FILES[*]}"
            fi
            
            return 1
        fi
        
        # 检查是否有待保存的修改
        if [[ "${CONFIG_DIRTY[$target_config_id]:-false}" != "true" ]]; then
            log_info "config" "配置没有待保存的修改: $target_config_id"
            
            # 即使没有待保存的修改，如果指定了目标文件，也复制当前配置
            if [[ -n "$target_file" ]]; then
                local source_file="${CONFIG_FILES[$target_config_id]}"
                
                # 创建目标目录（如果不存在）
                local target_dir
                target_dir="$(dirname "$target_file")"
                if [[ ! -d "$target_dir" ]]; then
                    mkdir -p "$target_dir" || {
                        log_error "config" "创建目标目录失败: $target_dir"
                        return 1
                    }
                fi
                
                # 复制文件
                if cp "$source_file" "$target_file"; then
                    log_info "config" "配置文件已复制到: $target_file"
                    return 0
                else
                    log_error "config" "复制配置文件失败"
                    return 1
                fi
            fi
            
            return 0
        fi
        
        # 保存指定配置
        if _config_save_single "$target_config_id" "$target_file"; then
            if [[ -n "$target_file" ]]; then
                log_info "config" "配置保存成功: $target_config_id -> $target_file"
            else
                log_info "config" "配置保存成功: $target_config_id"
            fi
            return 0
        else
            log_error "config" "配置保存失败: $target_config_id"
            return 1
        fi
    fi
    
    # 保存所有dirty的配置
    local config_ids=()
    for config_id in "${!CONFIG_DIRTY[@]}"; do
        if [[ "${CONFIG_DIRTY[$config_id]}" == "true" ]]; then
            config_ids+=("$config_id")
        fi
    done
    
    # 检查是否有待保存的配置
    if [[ ${#config_ids[@]} -eq 0 ]]; then
        log_info "config" "没有待保存的配置修改"
        return 0
    fi
    
    log_info "config" "开始批量保存配置 (共 ${#config_ids[@]} 个)"
    
    # 遍历所有待保存的配置
    for config_id in "${config_ids[@]}"; do
        if _config_save_single "$config_id"; then
            ((saved_count++))
            log_info "config" "  ✓ $config_id 保存成功"
        else
            ((failed_count++))
            log_error "config" "  ✗ $config_id 保存失败"
        fi
    done
    
    # 输出保存结果
    if [[ $failed_count -eq 0 ]]; then
        log_info "config" "批量保存完成: 成功 $saved_count 个"
        return 0
    else
        log_warn "config" "批量保存完成: 成功 $saved_count 个, 失败 $failed_count 个"
        return 1
    fi
}

# 内部函数: 保存单个配置的所有待保存修改
# 参数: 
#   $1 - 配置标识符
#   $2 - 目标文件路径(可选，默认保存到原文件)
# 返回: 0-成功, 1-失败
function _config_save_single() {
    local config_id="$1"
    local target_file="${2:-}"
    
    log_debug "config" "保存配置修改: $config_id, 目标文件: ${target_file:-(原文件)}"
    
    # 获取配置文件信息
    local source_file="${CONFIG_FILES[$config_id]}"
    local format="${CONFIG_FILE_FORMAT[$config_id]}"
    local pending_count="${CONFIG_PENDING_COUNT[$config_id]:-0}"
    
    # 确定实际操作的文件
    local config_file
    if [[ -n "$target_file" ]]; then
        # 如果指定了目标文件，先复制源文件到目标位置
        local target_dir
        target_dir="$(dirname "$target_file")"
        
        # 创建目标目录（如果不存在）
        if [[ ! -d "$target_dir" ]]; then
            mkdir -p "$target_dir" || {
                log_error "config" "创建目标目录失败: $target_dir"
                return 1
            }
        fi
        
        # 复制源文件到目标位置
        if ! cp "$source_file" "$target_file"; then
            log_error "config" "复制文件失败: $source_file -> $target_file"
            return 1
        fi
        
        config_file="$target_file"
        log_debug "config" "将保存到指定文件: $target_file"
    else
        # 保存到原文件
        config_file="$source_file"
        log_debug "config" "将保存到原文件: $source_file"
    fi
    
    if [[ $pending_count -eq 0 ]]; then
        log_debug "config" "没有待保存的修改: $config_id"
        CONFIG_DIRTY["$config_id"]="false"
        return 0
    fi
    
    log_debug "config" "应用 $pending_count 个待保存的修改"
    
    # 创建备份文件
    local backup_file="${config_file}.bak.$(date +%s)"
    if ! cp "$config_file" "$backup_file" 2>/dev/null; then
        log_error "config" "创建备份文件失败: $backup_file"
        return 1
    fi
    
    # 应用所有待保存的修改
    local i=0
    local success=true
    
    while [[ $i -lt $pending_count ]]; do
        local change_key="${config_id}:${i}"
        local change_data="${CONFIG_PENDING_CHANGES[$change_key]:-}"
        
        if [[ -z "$change_data" ]]; then
            ((i++))
            continue
        fi
        
        # 解析修改数据: operation_type|key|value|value_type
        IFS='|' read -r operation key value value_type <<< "$change_data"
        
        log_debug "config" "  [$((i+1))/$pending_count] 操作: $operation, 键: $key"
        
        # 执行操作
        case "$operation" in
            set)
                # 调用格式处理器写入
                case "$format" in
                    yaml)
                        if ! yaml_write "$config_file" "$key" "$value" "$value_type"; then
                            log_error "config" "    YAML写入失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    json)
                        if ! json_write "$config_file" "$key" "$value" "$value_type"; then
                            log_error "config" "    JSON写入失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    env)
                        if ! env_write "$config_file" "$key" "$value"; then
                            log_error "config" "    ENV写入失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    ini)
                        local section="${key%%.*}"
                        local ini_key="${key#*.}"
                        if ! ini_write "$config_file" "$section" "$ini_key" "$value"; then
                            log_error "config" "    INI写入失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    *)
                        log_error "config" "    不支持的格式: $format"
                        success=false
                        break
                        ;;
                esac
                ;;
            delete)
                # 调用格式处理器删除
                case "$format" in
                    yaml)
                        if ! yaml_delete "$config_file" "$key"; then
                            log_error "config" "    YAML删除失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    json)
                        if ! json_config_delete "$config_file" "$key"; then
                            log_error "config" "    JSON删除失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    env)
                        if ! env_delete "$config_file" "$key"; then
                            log_error "config" "    ENV删除失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    ini)
                        local section="${key%%.*}"
                        local ini_key="${key#*.}"
                        if ! ini_delete "$config_file" "$section" "$ini_key"; then
                            log_error "config" "    INI删除失败: $key"
                            success=false
                            break
                        fi
                        ;;
                    *)
                        log_error "config" "    不支持的格式: $format"
                        success=false
                        break
                        ;;
                esac
                ;;
            *)
                log_error "config" "    未知操作类型: $operation"
                success=false
                break
                ;;
        esac
        
        ((i++))
    done
    
    # 处理保存结果
    if [[ "$success" == "true" ]]; then
        # 保存成功，删除备份
        rm -f "$backup_file"
        
        # 清除所有待保存的修改
        i=0
        while [[ $i -lt $pending_count ]]; do
            unset "CONFIG_PENDING_CHANGES[${config_id}:${i}]"
            ((i++))
        done
        
        # 重置计数器和dirty标记
        CONFIG_PENDING_COUNT["$config_id"]=0
        CONFIG_DIRTY["$config_id"]="false"
        
        # 如果保存到原文件，更新文件哈希
        if [[ "$config_file" == "$source_file" ]]; then
            CONFIG_FILE_HASH["$config_id"]=$(_config_calculate_hash "$config_file")
            log_debug "config" "配置保存成功，已应用 $pending_count 个修改并更新哈希"
        else
            log_debug "config" "配置已导出到目标文件: $config_file (原文件未更改)"
        fi
        
        return 0
    else
        # 保存失败，恢复备份
        if mv "$backup_file" "$config_file" 2>/dev/null; then
            log_warn "config" "配置保存失败，已恢复备份"
        else
            log_error "config" "配置保存失败，且无法恢复备份！"
        fi
        return 1
    fi
}

# 函数: 获取配置文件路径
# 功能: 获取已加载配置的文件路径
# 参数:
#   $1 - 配置标识符
# 返回: 文件路径(stdout), 0-成功, 1-失败
# 示例:
#   config_file=$(config_get_file "logger")
function config_get_file() {
    local config_id="$1"
    
    if [[ -z "${CONFIG_FILES[$config_id]:-}" ]]; then
        log_error "config" "配置未加载: $config_id"
        return 1
    fi
    
    echo "${CONFIG_FILES[$config_id]}"
    return 0
}

# 函数: 获取配置格式
# 功能: 获取已加载配置的格式
# 参数:
#   $1 - 配置标识符
# 返回: 格式名称(stdout), 0-成功, 1-失败
# 示例:
#   format=$(config_get_format "logger")
function config_get_format() {
    local config_id="$1"
    
    if [[ -z "${CONFIG_FILE_FORMAT[$config_id]:-}" ]]; then
        log_error "config" "配置未加载: $config_id"
        return 1
    fi
    
    echo "${CONFIG_FILE_FORMAT[$config_id]}"
    return 0
}

# 函数: 列出所有已加载的配置
# 功能: 列出所有已加载的配置标识符
# 参数: 无
# 返回: 配置标识符列表(stdout)
# 示例:
#   config_list
function config_list() {
    if [[ ${#CONFIG_FILES[@]} -eq 0 ]]; then
        log_info "config" "当前没有已加载的配置"
        return 0
    fi
    
    log_info "config" "已加载的配置列表:"
    for config_id in "${!CONFIG_FILES[@]}"; do
        local file="${CONFIG_FILES[$config_id]}"
        local format="${CONFIG_FILE_FORMAT[$config_id]}"
        local hash="${CONFIG_FILE_HASH[$config_id]}"
        echo "  - $config_id: $file ($format) [hash: ${hash:0:8}...]"
    done
    
    return 0
}

# 函数: 显示帮助信息
# 功能: 显示配置管理模块的使用帮助
# 参数: 无
# 返回: 0
function config_help() {
    cat << 'EOF'
配置管理模块 (config.sh) - 使用说明

功能概述:
  提供统一的配置文件管理接口，支持多种配置格式（YAML、JSON、ENV、INI等）

核心功能:
  config_init                                    - 初始化配置系统
  config_load <file> [id] [force]                - 加载配置文件
  config_get <id> <key> [default]                - 读取配置值
  config_set <id> <key> <value> [type] [save]    - 写入配置值
  config_delete <id> <key> [save]                - 删除配置项
  config_save [id] [file]                        - 保存配置修改（批量保存/导出）
  config_reload <id>                             - 重新加载配置

辅助功能:
  config_get_file <id>                           - 获取配置文件路径
  config_get_format <id>                         - 获取配置格式
  config_list                                    - 列出所有已加载配置

支持的格式:
  - YAML (.yaml, .yml)       - 推荐格式，功能最完善
  - JSON (.json)             - 结构化数据格式
  - ENV  (.env)              - 环境变量格式
  - INI  (.ini, .conf, .cfg) - 传统配置格式

参数说明:
  file    - 配置文件路径
  id      - 配置标识符（可选，默认使用文件名）
  key     - 配置键路径（YAML/JSON: .key.subkey, INI: section.key）
  value   - 要设置的值
  type    - 值类型: string(默认) | number | boolean
  default - 默认值（当配置项不存在时返回）
  force   - 是否强制重载（true/false，默认false）

使用示例:

  # 1. 初始化配置系统
  config_init

  # 2. 加载配置文件
  config_load "config/logger.yaml" "logger"
  config_load "config/mysql.ini" "mysql"

  # 3. 读取配置值
  log_level=$(config_get "logger" ".logger.global.level" "INFO")
  db_port=$(config_get "mysql" "database.port" "3306")

  # 4. 写入配置值（立即保存）
  config_set "logger" ".logger.global.level" "DEBUG"
  config_set "mysql" "database.port" "3307" "number"

  # 5. 批量修改场景（延迟保存）
  config_set "logger" ".logger.global.level" "DEBUG" "string" false
  config_set "logger" ".logger.global.async" "true" "boolean" false
  config_set "logger" ".logger.global.format" "json" "string" false
  config_save "logger"  # 一次性保存所有修改

  # 6. 跨配置批量修改
  config_set "logger" ".level" "DEBUG" "string" false
  config_set "mysql" "database.port" "3307" "number" false
  config_save  # 保存所有配置的修改

  # 7. 保存到指定文件（导出/备份）
  config_save "logger" "backup/logger.yaml"            # 导出到备份目录
  config_save "logger" "/tmp/logger_export.yaml"       # 导出到临时目录
  
  # 8. 批量修改并导出
  config_set "logger" ".level" "PRODUCTION" "string" false
  config_save "logger" "config/prod/logger.yaml"       # 导出为生产配置

  # 9. 删除配置项
  config_delete "logger" ".logger.test_key"
  config_delete "logger" ".logger.old_key" false       # 延迟保存

  # 10. 重新加载配置
  config_reload "logger"

  # 11. 列出所有配置
  config_list

高级特性:
  - 自动格式识别：根据文件扩展名自动选择处理器
  - 自动重载：检测文件变更自动刷新（可通过 CONFIG_AUTO_RELOAD 控制）
  - 配置缓存：基于哈希值的缓存失效策略，避免重复解析
  - 原子操作：所有写操作都包含备份-修改-验证-恢复机制
  - 批量保存：支持延迟保存，批量修改后统一提交，提升性能
  - 配置导出：支持保存到指定文件，方便备份和多环境配置管理

环境变量:
  CONFIG_AUTO_RELOAD   - 是否自动检测变更并重载（默认: true）
  CONFIG_CACHE_ENABLED - 是否启用缓存（默认: true）

注意事项:
  1. INI格式的键路径必须是 section.key 格式
  2. YAML/JSON的键路径以点号分隔，如 .root.child.key
  3. 配置文件修改后会自动更新哈希值，支持变更检测
  4. 所有写操作都是原子的，失败时会自动恢复

EOF
    return 0
}

###############################################################################
# 日志函数（如果外部日志模块不可用，提供简单实现）
###############################################################################

if ! command -v log_debug >/dev/null 2>&1; then
    function log_debug() {
        local module="${1:-}"
        shift
        echo "[DEBUG] [$module] $*" >&2
    }
fi

if ! command -v log_info >/dev/null 2>&1; then
    function log_info() {
        local module="${1:-}"
        shift
        echo "[INFO]  [$module] $*" >&2
    }
fi

if ! command -v log_warn >/dev/null 2>&1; then
    function log_warn() {
        local module="${1:-}"
        shift
        echo "[WARN]  [$module] $*" >&2
    }
fi

if ! command -v log_error >/dev/null 2>&1; then
    function log_error() {
        local module="${1:-}"
        shift
        echo "[ERROR] [$module] $*" >&2
    }
fi

###############################################################################
# 模块初始化（可选：自动初始化）
###############################################################################

# 如果设置了自动初始化环境变量，则自动执行初始化
if [[ "${CONFIG_AUTO_INIT:-false}" == "true" ]]; then
    config_init
fi

